package com.glsx.auto;

import com.google.common.base.CaseFormat;
import org.apache.commons.lang3.StringUtils;

import java.sql.*;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by linxy on 2017/4/28.
 */
public class Table {
    private String tableName;
    private String comment;
    private String javaBeanName;
    private Column primaryColumn;
    private List<Column> columns = new ArrayList<Column>();

    public static class Column {
        private Class<?> type;
        private String name;
        private String fieldName;
        private String comment;
        private boolean isPrimaryKey;

        public Column(Class<?> type, String name, String comment, boolean isPrimaryKey) {
            this.type = type;
            this.name = name;
            this.comment = comment;
            this.isPrimaryKey = isPrimaryKey;

            fieldName = CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, name);
        }

        public Class<?> getType() {
            return type;
        }

        public void setType(Class<?> type) {
            this.type = type;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getComment() {
            return comment;
        }

        public void setComment(String comment) {
            this.comment = comment;
        }

        public boolean isPrimaryKey() {
            return isPrimaryKey;
        }

        public void setPrimaryKey(boolean primaryKey) {
            isPrimaryKey = primaryKey;
        }

        public String getFieldName() {
            return fieldName;
        }

        public String toGetMethodName() {
            return "get"+CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL, getFieldName());
        }

        public String toSetMethodName() {
            return "set"+CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL, getFieldName());
        }
    }


    private static Class<?> getClassType(int type) {
        Class<?> clazz = String.class;

        switch (type) {

            case Types.NUMERIC:
            case Types.DECIMAL:
                clazz = java.math.BigDecimal.class;
                break;

            case Types.BIT:
                clazz = java.lang.Boolean.class;
                break;

            case Types.TINYINT:
                clazz = java.lang.Byte.class;
                break;

            case Types.SMALLINT:
                clazz = java.lang.Short.class;
                break;

            case Types.INTEGER:
                clazz = java.lang.Integer.class;
                break;

            case Types.BIGINT:
                clazz = java.lang.Long.class;
                break;

            case Types.REAL:
                clazz = java.lang.Float.class;
                break;

            case Types.FLOAT:
            case Types.DOUBLE:
                clazz = java.lang.Double.class;
                break;

            case Types.BINARY:
            case Types.VARBINARY:
            case Types.LONGVARBINARY:
                try {
                    clazz = Class.forName("byte[]");
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
                break;

            case Types.DATE:
                clazz = java.sql.Date.class;
                break;

            case Types.TIME:
                clazz = java.sql.Time.class;
                break;

            case Types.TIMESTAMP:
                clazz = java.sql.Timestamp.class;
                break;

            case Types.BLOB:
                clazz = java.sql.Blob.class;
                break;

            case Types.CLOB:
                clazz = java.sql.Clob.class;
                break;
        }

        return clazz;
    }


    public Table(String tableName, String eraseTablePrefix) {
        this.tableName = tableName;
        javaBeanName = tableName;
        if(!StringUtils.isEmpty(eraseTablePrefix) && tableName.startsWith(eraseTablePrefix)) {
            javaBeanName = CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, javaBeanName.substring(eraseTablePrefix.length()));
        }
        javaBeanName = CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, javaBeanName);
    }

    private void populateComment(Connection connection) throws SQLException {
        Statement stmt = connection.createStatement();
        ResultSet rs = stmt.executeQuery("SHOW CREATE TABLE " + tableName);
        if(rs.next()) {
            String create = rs.getString(2);
            int index = create.indexOf("COMMENT='");
            if(index < 0) {
                return;
            }
            comment = create.substring(index+9);
            comment = comment.substring(0,comment.length() - 1);
        }
    }

    public void populateColumn(Connection connection) throws SQLException {

        ResultSet resultSet;
        String primaryKeyColumnName = null;

        DatabaseMetaData metaData = connection.getMetaData();

        populateComment(connection);

        resultSet = metaData.getPrimaryKeys("", "", tableName);
        while (resultSet.next()) {
            primaryKeyColumnName = resultSet.getString("COLUMN_NAME");
        }

        resultSet = metaData.getColumns("", "", tableName, "%");
        while (resultSet.next()) {
            String columnName = resultSet.getString("COLUMN_NAME");
            String remark = resultSet.getString("REMARKS");
            String dataType = resultSet.getString("DATA_TYPE");

            boolean isPrimaryKey = columnName.equals(primaryKeyColumnName);

            Column column = new Column(getClassType(Integer.parseInt(dataType)), columnName, remark, isPrimaryKey);
            if(isPrimaryKey) {
                primaryColumn = column;
            }
            this.columns.add(column);
        }
    }

    public String getComment() {
        return comment;
    }

    public void setComment(String comment) {
        this.comment = comment;
    }

    public Column getPrimaryColumn() {
        return primaryColumn;
    }

    public void setPrimaryColumn(Column primaryColumn) {
        this.primaryColumn = primaryColumn;
    }

    public String getTableName() {
        return tableName;
    }

    public void setTableName(String tableName) {
        this.tableName = tableName;
    }

    public List<Column> getColumns() {
        return columns;
    }

    public void setColumns(List<Column> columns) {
        this.columns = columns;
    }

    public String getJavaBeanName() {
        return javaBeanName;
    }
}
